ISB Presentation Draft

#F0 136 to 280 ms

# Load data
ERP_F0_long <- readr::read_csv("tidy_data_all_erps/ERP_F0_long.csv")
## Rows: 12276 Columns: 8
## ── Column specification ────────────────────────────────────────────────────────
## Delimiter: ","
## chr (7): Participant_ID, L1_L2, area, time_period, channel, stress, match
## dbl (1): amplitude
## 
## ℹ Use `spec()` to retrieve the full column specification for this data.
## ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
# Create subject ID 
ERP_F0_long <- ERP_F0_long %>%
  mutate(Subject_ID = paste(Participant_ID, L1_L2, sep = "_"))

# Filter 
f0_136_data <- ERP_F0_long %>%
  filter(time_period == "136_280",
         channel %in% c("F3", "FZ", "FC1", "CZ"))

# Repeated-measures ANOVA
aov_pran_136 <- aov_ez(
  id = "Subject_ID",
  dv = "amplitude",
  within = c("stress", "match"),
  between = "L1_L2",
  data = f0_136_data,
  type = 3
)
## Converting to factor: L1_L2
## Warning: More than one observation per design cell, aggregating data using `fun_aggregate = mean`.
## To turn off this warning, pass `fun_aggregate = mean` explicitly.
## Contrasts set to contr.sum for the following variables: L1_L2
# ANOVA summary
summary(aov_pran_136)
## 
## Univariate Type III Repeated-Measures ANOVA Assuming Sphericity
## 
##                    Sum Sq num Df Error SS den Df F value  Pr(>F)  
## (Intercept)        51.804      1   288.40     29  5.2092 0.02999 *
## L1_L2               1.591      1   288.40     29  0.1600 0.69208  
## stress             19.779      1   243.44     29  2.3562 0.13563  
## L1_L2:stress       18.974      1   243.44     29  2.2604 0.14354  
## match              16.621      1   125.54     29  3.8394 0.05974 .
## L1_L2:match         4.138      1   125.54     29  0.9558 0.33634  
## stress:match       24.418      1   171.71     29  4.1238 0.05154 .
## L1_L2:stress:match 27.696      1   171.71     29  4.6775 0.03894 *
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
# Estimated marginal means
em <- emmeans(aov_pran_136, ~ stress * match * L1_L2)
kable(as.data.frame(em), digits = 2)
stress match L1_L2 emmean SE df lower.CL upper.CL
stressed mismatch L1 -2.14 1.30 29 -4.80 0.52
unstressed mismatch L1 -1.76 1.27 29 -4.36 0.83
stressed match L1 2.23 1.19 29 -0.20 4.66
unstressed match L1 -2.86 1.56 29 -6.05 0.33
stressed mismatch L2 -1.01 0.50 29 -2.04 0.01
unstressed mismatch L2 -1.12 0.49 29 -2.12 -0.13
stressed match L2 -0.55 0.46 29 -1.49 0.38
unstressed match L2 -0.49 0.60 29 -1.72 0.74
knitr::kable(nice(aov_pran_136), caption = "F0 136–280 ms Repeated Measures ANOVA") %>%
  kable_styling(full_width = FALSE)
F0 136–280 ms Repeated Measures ANOVA
Effect df MSE F ges p.value
L1_L2 1, 29 9.94 0.16 .002 .692
stress 1, 29 8.39 2.36 .023 .136
L1_L2:stress 1, 29 8.39 2.26 .022 .144
match 1, 29 4.33 3.84 + .020 .060
L1_L2:match 1, 29 4.33 0.96 .005 .336
stress:match 1, 29 5.92 4.12 + .029 .052
L1_L2:stress:match 1, 29 5.92 4.68 * .032 .039

#F0 280-400 ms

# Filter
f0_280_data <- ERP_F0_long %>%
  filter(time_period == "280_400",
         channel %in% c("F3", "FZ", "FC1", "CZ"))

# Repeated-measures ANOVA
aov_pran_280 <- aov_ez(
  id = "Subject_ID",
  dv = "amplitude",
  within = c("stress", "match"),
  between = "L1_L2",
  data = f0_280_data,
  type = 3,
  return = "afex_aov"
)
## Converting to factor: L1_L2
## Warning: More than one observation per design cell, aggregating data using `fun_aggregate = mean`.
## To turn off this warning, pass `fun_aggregate = mean` explicitly.
## Contrasts set to contr.sum for the following variables: L1_L2
# ANOVA summary
summary(aov_pran_280)
## 
## Univariate Type III Repeated-Measures ANOVA Assuming Sphericity
## 
##                    Sum Sq num Df Error SS den Df F value  Pr(>F)  
## (Intercept)        46.079      1   512.44     29  2.6077 0.11718  
## L1_L2               0.104      1   512.44     29  0.0059 0.93925  
## stress              6.392      1   251.02     29  0.7385 0.39720  
## L1_L2:stress        8.539      1   251.02     29  0.9864 0.32883  
## match               1.868      1   214.16     29  0.2529 0.61882  
## L1_L2:match         1.252      1   214.16     29  0.1696 0.68350  
## stress:match       39.335      1   209.54     29  5.4440 0.02678 *
## L1_L2:stress:match 35.255      1   209.54     29  4.8793 0.03524 *
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
# Estimated marginal means
emmeans(aov_pran_280, ~ stress * match * L1_L2)
##  stress     match    L1_L2 emmean    SE df lower.CL upper.CL
##  stressed   mismatch L1    -2.191 1.780 29    -5.84    1.455
##  unstressed mismatch L1    -0.380 1.250 29    -2.95    2.185
##  stressed   match    L1     1.746 1.410 29    -1.14    4.633
##  unstressed match    L1    -2.985 1.870 29    -6.81    0.837
##  stressed   mismatch L2    -0.997 0.686 29    -2.40    0.406
##  unstressed mismatch L2    -0.802 0.483 29    -1.79    0.186
##  stressed   match    L2    -0.841 0.543 29    -1.95    0.271
##  unstressed match    L2    -0.825 0.719 29    -2.30    0.646
## 
## Confidence level used: 0.95
knitr::kable(nice(aov_pran_280), caption = "F0 280–400 ms Repeated Measures ANOVA") %>%
  kable_styling(full_width = FALSE)
F0 280–400 ms Repeated Measures ANOVA
Effect df MSE F ges p.value
L1_L2 1, 29 17.67 0.01 <.001 .939
stress 1, 29 8.66 0.74 .005 .397
L1_L2:stress 1, 29 8.66 0.99 .007 .329
match 1, 29 7.38 0.25 .002 .619
L1_L2:match 1, 29 7.38 0.17 .001 .684
stress:match 1, 29 7.23 5.44 * .032 .027
L1_L2:stress:match 1, 29 7.23 4.88 * .029 .035

F0 400 to 600 ms

# Filter
f0_400_data <- ERP_F0_long %>%
  filter(time_period == "400_600",
         channel %in% c("F3", "FZ", "FC1", "CZ")) 

# Repeated-measures ANOVA
aov_pran_400 <- aov_ez(
  id = "Subject_ID",
  dv = "amplitude",
  within = c("stress", "match"),
  between = "L1_L2",
  data = f0_400_data,
  type = 3,
  return = "afex_aov"
)
## Converting to factor: L1_L2
## Warning: More than one observation per design cell, aggregating data using `fun_aggregate = mean`.
## To turn off this warning, pass `fun_aggregate = mean` explicitly.
## Contrasts set to contr.sum for the following variables: L1_L2
# ANOVA summary
summary(aov_pran_400)
## 
## Univariate Type III Repeated-Measures ANOVA Assuming Sphericity
## 
##                    Sum Sq num Df Error SS den Df F value  Pr(>F)  
## (Intercept)        62.082      1   694.84     29  2.5911 0.11830  
## L1_L2               0.241      1   694.84     29  0.0100 0.92085  
## stress             15.183      1   248.08     29  1.7749 0.19315  
## L1_L2:stress       14.489      1   248.08     29  1.6938 0.20335  
## match              12.120      1   340.32     29  1.0328 0.31791  
## L1_L2:match         1.935      1   340.32     29  0.1648 0.68771  
## stress:match       80.040      1   467.96     29  4.9601 0.03386 *
## L1_L2:stress:match 78.949      1   467.96     29  4.8925 0.03501 *
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
# Estimated marginal means
emmeans(aov_pran_400, ~ stress * match * L1_L2)
##  stress     match    L1_L2 emmean    SE df lower.CL upper.CL
##  stressed   mismatch L1    -1.694 2.330 29    -6.45    3.067
##  unstressed mismatch L1     1.020 1.350 29    -1.74    3.775
##  stressed   match    L1     1.778 1.520 29    -1.33    4.885
##  unstressed match    L1    -5.062 2.360 29    -9.88   -0.241
##  stressed   mismatch L2    -0.837 0.896 29    -2.67    0.995
##  unstressed mismatch L2    -0.845 0.519 29    -1.91    0.216
##  stressed   match    L2    -1.381 0.585 29    -2.58   -0.185
##  unstressed match    L2    -1.421 0.907 29    -3.28    0.434
## 
## Confidence level used: 0.95
knitr::kable(nice(aov_pran_400), caption = "F0 400–600 ms Repeated Measures ANOVA") %>%
  kable_styling(full_width = FALSE)
F0 400–600 ms Repeated Measures ANOVA
Effect df MSE F ges p.value
L1_L2 1, 29 23.96 0.01 <.001 .921
stress 1, 29 8.55 1.77 .009 .193
L1_L2:stress 1, 29 8.55 1.69 .008 .203
match 1, 29 11.74 1.03 .007 .318
L1_L2:match 1, 29 11.74 0.16 .001 .688
stress:match 1, 29 16.14 4.96 * .044 .034
L1_L2:stress:match 1, 29 16.14 4.89 * .043 .035

Suffix 235 to 415 ms

ERP_suffix_long <- readr::read_csv("tidy_data_all_erps/ERP_suffix_long.csv")
## Rows: 16368 Columns: 8
## ── Column specification ────────────────────────────────────────────────────────
## Delimiter: ","
## chr (7): Participant_ID, L1_L2, area, time_period, channel, stress, match
## dbl (1): amplitude
## 
## ℹ Use `spec()` to retrieve the full column specification for this data.
## ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
ERP_suffix_long <- ERP_suffix_long %>%
  mutate(Subject_ID = paste(Participant_ID, L1_L2, sep = "_"))

# 235–415 ms
suffix_235_data <- ERP_suffix_long %>%
  filter(time_period == "235_415",
         channel %in% c("F7", "F3", "FC5"))

aov_suffix_235 <- aov_ez(
  id = "Subject_ID",
  dv = "amplitude",
  within = c("stress", "match"),
  between = "L1_L2",
  data = suffix_235_data,
  type = 3,
  return = "afex_aov"
)
## Converting to factor: L1_L2
## Warning: More than one observation per design cell, aggregating data using `fun_aggregate = mean`.
## To turn off this warning, pass `fun_aggregate = mean` explicitly.
## Contrasts set to contr.sum for the following variables: L1_L2
# View summary
summary(aov_suffix_235)
## 
## Univariate Type III Repeated-Measures ANOVA Assuming Sphericity
## 
##                    Sum Sq num Df Error SS den Df F value Pr(>F)
## (Intercept)        55.305      1  1727.59     29  0.9284 0.3433
## L1_L2              31.846      1  1727.59     29  0.5346 0.4706
## stress             17.391      1   463.37     29  1.0884 0.3054
## L1_L2:stress        4.665      1   463.37     29  0.2920 0.5931
## match               5.871      1  1100.55     29  0.1547 0.6970
## L1_L2:match         0.919      1  1100.55     29  0.0242 0.8774
## stress:match       16.966      1   822.70     29  0.5981 0.4456
## L1_L2:stress:match 34.171      1   822.70     29  1.2045 0.2814
# Post-hoc comparisons
emmeans(aov_suffix_235, ~ stress * match * L1_L2)
##  stress     match    L1_L2  emmean    SE df lower.CL upper.CL
##  stressed   mismatch L1    -1.7858 4.540 29   -11.07    7.496
##  unstressed mismatch L1    -0.8122 2.070 29    -5.05    3.421
##  stressed   match    L1    -0.0223 2.040 29    -4.19    4.145
##  unstressed match    L1    -4.3874 2.540 29    -9.58    0.801
##  stressed   mismatch L2     0.4565 1.750 29    -3.12    4.029
##  unstressed mismatch L2    -0.5446 0.797 29    -2.17    1.085
##  stressed   match    L2    -0.3984 0.784 29    -2.00    1.206
##  unstressed match    L2    -0.4744 0.976 29    -2.47    1.523
## 
## Confidence level used: 0.95
knitr::kable(nice(aov_suffix_235), caption = "Suffix 235–415 ms Repeated Measures ANOVA") %>%
  kable_styling(full_width = FALSE)
Suffix 235–415 ms Repeated Measures ANOVA
Effect df MSE F ges p.value
L1_L2 1, 29 59.57 0.53 .008 .471
stress 1, 29 15.98 1.09 .004 .305
L1_L2:stress 1, 29 15.98 0.29 .001 .593
match 1, 29 37.95 0.15 .001 .697
L1_L2:match 1, 29 37.95 0.02 <.001 .877
stress:match 1, 29 28.37 0.60 .004 .446
L1_L2:stress:match 1, 29 28.37 1.20 .008 .281

Suffix 415-550 ms

suffix_415_data <- ERP_suffix_long %>%
  filter(time_period == "415_550",
         channel %in% c("F7", "F3", "FC5"))

aov_suffix_415 <- aov_ez(
  id = "Subject_ID",
  dv = "amplitude",
  within = c("stress", "match"),
  between = "L1_L2",
  data = suffix_415_data,
  type = 3,
  return = "afex_aov"
)
## Converting to factor: L1_L2
## Warning: More than one observation per design cell, aggregating data using `fun_aggregate = mean`.
## To turn off this warning, pass `fun_aggregate = mean` explicitly.
## Contrasts set to contr.sum for the following variables: L1_L2
summary(aov_suffix_415)
## 
## Univariate Type III Repeated-Measures ANOVA Assuming Sphericity
## 
##                    Sum Sq num Df Error SS den Df F value Pr(>F)
## (Intercept)         0.432      1  1864.86     29  0.0067 0.9352
## L1_L2               0.704      1  1864.86     29  0.0109 0.9174
## stress             12.737      1   398.54     29  0.9268 0.3437
## L1_L2:stress        6.488      1   398.54     29  0.4721 0.4975
## match               8.418      1  1448.90     29  0.1685 0.6845
## L1_L2:match        21.446      1  1448.90     29  0.4293 0.5175
## stress:match       32.774      1  1311.21     29  0.7249 0.4015
## L1_L2:stress:match 64.226      1  1311.21     29  1.4205 0.2430
emmeans(aov_suffix_415, ~ stress * match * L1_L2)
##  stress     match    L1_L2  emmean    SE df lower.CL upper.CL
##  stressed   mismatch L1    -2.0056 5.350 29  -12.943    8.932
##  unstressed mismatch L1     0.0364 1.980 29   -4.009    4.082
##  stressed   match    L1     3.6926 1.980 29   -0.358    7.743
##  unstressed match    L1    -1.6262 2.620 29   -6.988    3.736
##  stressed   mismatch L2     0.4747 2.060 29   -3.735    4.685
##  unstressed mismatch L2    -0.4122 0.761 29   -1.969    1.145
##  stressed   match    L2    -0.6018 0.762 29   -2.161    0.957
##  unstressed match    L2    -0.2623 1.010 29   -2.326    1.802
## 
## Confidence level used: 0.95
knitr::kable(nice(aov_suffix_415), caption = "Suffix 415–550 ms Repeated Measures ANOVA") %>%
  kable_styling(full_width = FALSE)
Suffix 415–550 ms Repeated Measures ANOVA
Effect df MSE F ges p.value
L1_L2 1, 29 64.31 0.01 <.001 .917
stress 1, 29 13.74 0.93 .003 .344
L1_L2:stress 1, 29 13.74 0.47 .001 .497
match 1, 29 49.96 0.17 .002 .684
L1_L2:match 1, 29 49.96 0.43 .004 .518
stress:match 1, 29 45.21 0.72 .006 .402
L1_L2:stress:match 1, 29 45.21 1.42 .013 .243

Suffix 550-680 ms

suffix_550_data <- ERP_suffix_long %>%
  filter(time_period == "550_680",
         channel %in% c("F7", "F3", "FC5"))

aov_suffix_550 <- aov_ez(
  id = "Subject_ID",
  dv = "amplitude",
  within = c("stress", "match"),
  between = "L1_L2",
  data = suffix_550_data,
  type = 3,
  return = "afex_aov"
)
## Converting to factor: L1_L2
## Warning: More than one observation per design cell, aggregating data using `fun_aggregate = mean`.
## To turn off this warning, pass `fun_aggregate = mean` explicitly.
## Contrasts set to contr.sum for the following variables: L1_L2
summary(aov_suffix_550)
## 
## Univariate Type III Repeated-Measures ANOVA Assuming Sphericity
## 
##                     Sum Sq num Df Error SS den Df F value  Pr(>F)  
## (Intercept)          0.009      1   3431.8     29  0.0001 0.99294  
## L1_L2                6.469      1   3431.8     29  0.0547 0.81678  
## stress               0.374      1    725.0     29  0.0150 0.90349  
## L1_L2:stress         0.036      1    725.0     29  0.0015 0.96979  
## match                1.890      1   2046.6     29  0.0268 0.87115  
## L1_L2:match          2.366      1   2046.6     29  0.0335 0.85598  
## stress:match       104.190      1   2274.0     29  1.3287 0.25845  
## L1_L2:stress:match 239.655      1   2274.0     29  3.0562 0.09101 .
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
emmeans(aov_suffix_550, ~ stress * match * L1_L2)
##  stress     match    L1_L2 emmean    SE df lower.CL upper.CL
##  stressed   mismatch L1    -3.421 7.320 29  -18.389   11.547
##  unstressed mismatch L1     3.348 2.270 29   -1.296    7.992
##  stressed   match    L1     4.241 2.280 29   -0.429    8.911
##  unstressed match    L1    -2.753 3.030 29   -8.940    3.434
##  stressed   mismatch L2     0.508 2.820 29   -5.253    6.269
##  unstressed mismatch L2    -1.120 0.874 29   -2.907    0.668
##  stressed   match    L2    -0.948 0.879 29   -2.746    0.849
##  unstressed match    L2     0.249 1.160 29   -2.132    2.631
## 
## Confidence level used: 0.95
knitr::kable(nice(aov_suffix_550), caption = "Suffix 550–680 ms Repeated Measures ANOVA") %>%
  kable_styling(full_width = FALSE)
Suffix 550–680 ms Repeated Measures ANOVA
Effect df MSE F ges p.value
L1_L2 1, 29 118.34 0.05 <.001 .817
stress 1, 29 25.00 0.01 <.001 .903
L1_L2:stress 1, 29 25.00 0.00 <.001 .970
match 1, 29 70.57 0.03 <.001 .871
L1_L2:match 1, 29 70.57 0.03 <.001 .856
stress:match 1, 29 78.41 1.33 .012 .258
L1_L2:stress:match 1, 29 78.41 3.06 + .027 .091

Suffix 680-800 ms

suffix_680_data <- ERP_suffix_long %>%
  filter(time_period == "680_800",
         channel %in% c("F7", "F3", "FC5"))

aov_suffix_680 <- aov_ez(
  id = "Subject_ID",
  dv = "amplitude",
  within = c("stress", "match"),
  between = "L1_L2",
  data = suffix_680_data,
  type = 3,
  return = "afex_aov"
)
## Converting to factor: L1_L2
## Warning: More than one observation per design cell, aggregating data using `fun_aggregate = mean`.
## To turn off this warning, pass `fun_aggregate = mean` explicitly.
## Contrasts set to contr.sum for the following variables: L1_L2
# Summary of ANOVA
summary(aov_suffix_680)
## 
## Univariate Type III Repeated-Measures ANOVA Assuming Sphericity
## 
##                    Sum Sq num Df Error SS den Df F value  Pr(>F)  
## (Intercept)         77.30      1   5858.6     29  0.3826 0.54102  
## L1_L2                3.43      1   5858.6     29  0.0170 0.89718  
## stress               6.94      1    716.9     29  0.2808 0.60019  
## L1_L2:stress         0.71      1    716.9     29  0.0287 0.86659  
## match                3.89      1   1899.0     29  0.0594 0.80923  
## L1_L2:match         10.68      1   1899.0     29  0.1631 0.68929  
## stress:match       159.10      1   2314.6     29  1.9934 0.16863  
## L1_L2:stress:match 336.47      1   2314.6     29  4.2157 0.04917 *
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
# Estimated marginal means
emmeans(aov_suffix_680, ~ stress * match * L1_L2)
##  stress     match    L1_L2 emmean   SE df lower.CL upper.CL
##  stressed   mismatch L1    -5.808 7.47 29   -21.09    9.471
##  unstressed mismatch L1     1.553 2.78 29    -4.13    7.241
##  stressed   match    L1     3.888 3.43 29    -3.13   10.905
##  unstressed match    L1    -5.336 4.21 29   -13.94    3.267
##  stressed   mismatch L2     0.252 2.88 29    -5.63    6.133
##  unstressed mismatch L2    -1.763 1.07 29    -3.95    0.426
##  stressed   match    L2    -1.630 1.32 29    -4.33    1.070
##  unstressed match    L2    -0.576 1.62 29    -3.89    2.736
## 
## Confidence level used: 0.95
knitr::kable(nice(aov_suffix_680), caption = "Suffix 680–800 ms Repeated Measures ANOVA") %>%
  kable_styling(full_width = FALSE)
Suffix 680–800 ms Repeated Measures ANOVA
Effect df MSE F ges p.value
L1_L2 1, 29 202.02 0.02 <.001 .897
stress 1, 29 24.72 0.28 <.001 .600
L1_L2:stress 1, 29 24.72 0.03 <.001 .867
match 1, 29 65.48 0.06 <.001 .809
L1_L2:match 1, 29 65.48 0.16 <.001 .689
stress:match 1, 29 79.81 1.99 .015 .169
L1_L2:stress:match 1, 29 79.81 4.22 * .030 .049

Topographic plots

Topographical maps show the difference in mean ERP amplitude between stressed and unstressed conditions at F0 onset (electrodes: F3, Fz, FC1, Cz) and between mismatch and match conditions at suffix onset (electrodes: F7, F3, FC5) across time windows and groups (L1 vs. L2).Gray regions reflect areas outside the interpolation range based on selected electrodes.

f0_diff <- ERP_F0_long %>%
  filter(channel %in% c("F3", "Fz", "FC1", "Cz"),
         time_period %in% c("136_280", "280_400", "400_600")) %>%
  group_by(channel, L1_L2, stress, time_period) %>%
  summarise(mean_amp = mean(amplitude), .groups = "drop") %>%
  pivot_wider(names_from = stress, values_from = mean_amp) %>%
  mutate(diff = stressed - unstressed)

electrode_coords <- tibble::tribble(
  ~electrode, ~x,   ~y,
  "F3",       -0.4,  0.5,
  "Fz",        0.0,  0.7,
  "FC1",       0.3,  0.4,
  "Cz",        0.0,  0.0
)

f0_diff_coords <- f0_diff %>%
  rename(electrode = channel) %>%
  left_join(electrode_coords, by = "electrode")

ggplot(f0_diff_coords, aes(x = x, y = y, fill = diff, z = diff)) +
  geom_topo(interp_limit = "head", chan_markers = "point", colour = "black") +
  scale_fill_distiller(palette = "RdBu", limits = c(-5, 5)) +
  coord_equal() +
  theme_void() +
  facet_grid(L1_L2 ~ time_period) +
  labs(
    title = "Stressed – Unstressed at F0 Onset",
    fill = expression(Delta~Amplitude~(mu*V))
  )

# Optional: View just L2 values
f0_diff_coords %>%
  filter(L1_L2 == "L2") %>%
  select(electrode, time_period, diff)
## # A tibble: 12 × 3
##    electrode time_period    diff
##    <chr>     <chr>         <dbl>
##  1 Cz        136_280      0.575 
##  2 Cz        280_400      0.0533
##  3 Cz        400_600     -0.375 
##  4 F3        136_280     -0.337 
##  5 F3        280_400     -0.352 
##  6 F3        400_600     -0.0743
##  7 FC1       136_280      0.385 
##  8 FC1       280_400      0.141 
##  9 FC1       400_600      0.123 
## 10 Fz        136_280      0.660 
## 11 Fz        280_400      0.502 
## 12 Fz        400_600      0.478
# Optional: Confirm counts
ERP_F0_long %>%
  filter(channel %in% c("F3", "Fz", "FC1", "Cz"),
         time_period %in% c("136_280", "280_400", "400_600"),
         L1_L2 == "L2") %>%
  count(channel, time_period)
## # A tibble: 12 × 3
##    channel time_period     n
##    <chr>   <chr>       <int>
##  1 Cz      136_280       108
##  2 Cz      280_400       108
##  3 Cz      400_600       108
##  4 F3      136_280       108
##  5 F3      280_400       108
##  6 F3      400_600       108
##  7 FC1     136_280       108
##  8 FC1     280_400       108
##  9 FC1     400_600       108
## 10 Fz      136_280       108
## 11 Fz      280_400       108
## 12 Fz      400_600       108
# ==== SUFFIX ANALYSIS ====
suffix_diff <- ERP_suffix_long %>%
  filter(channel %in% c("F7", "F3", "FC5"),
         time_period %in% c("235_415", "415_550", "550_680", "680_800")) %>%
  group_by(channel, L1_L2, match, time_period) %>%
  summarise(mean_amp = mean(amplitude), .groups = "drop") %>%
  pivot_wider(names_from = match, values_from = mean_amp) %>%
  mutate(diff = mismatch - match)

electrode_coords_suffix <- tibble::tribble(
  ~electrode, ~x,   ~y,
  "F7",       -0.7,  0.3,
  "F3",       -0.4,  0.5,
  "FC5",      -0.5,  0.4
)

suffix_diff_coords <- suffix_diff %>%
  rename(electrode = channel) %>%
  left_join(electrode_coords_suffix, by = "electrode")

ggplot(suffix_diff_coords, aes(x = x, y = y, fill = diff, z = diff)) +
  geom_topo(interp_limit = "head", chan_markers = "point", colour = "black") +
  scale_fill_distiller(palette = "RdBu", limits = c(-5, 5)) +
  coord_equal() +
  theme_void() +
  facet_grid(L1_L2 ~ time_period) +
  labs(
    title = "Mismatch – Match at Suffix Onset",
    fill = expression(Delta~Amplitude~(mu*V))
  )

# Optional: View just L2 values
suffix_diff_coords %>%
  filter(L1_L2 == "L2") %>%
  select(electrode, time_period, diff)
## # A tibble: 12 × 3
##    electrode time_period    diff
##    <chr>     <chr>         <dbl>
##  1 F3        235_415      0.717 
##  2 F3        415_550      0.344 
##  3 F3        550_680     -0.0718
##  4 F3        680_800      0.305 
##  5 F7        235_415      0.435 
##  6 F7        415_550      0.771 
##  7 F7        550_680      0.295 
##  8 F7        680_800      0.548 
##  9 FC5       235_415      0.0257
## 10 FC5       415_550      0.275 
## 11 FC5       550_680     -0.0917
## 12 FC5       680_800      0.189
# Optional: Confirm counts
ERP_suffix_long %>%
  filter(channel %in% c("F7", "F3", "FC5"),
         time_period %in% c("235_415", "415_550", "550_680", "680_800"),
         L1_L2 == "L2") %>%
  count(channel, time_period)
## # A tibble: 12 × 3
##    channel time_period     n
##    <chr>   <chr>       <int>
##  1 F3      235_415       108
##  2 F3      415_550       108
##  3 F3      550_680       108
##  4 F3      680_800       108
##  5 F7      235_415       108
##  6 F7      415_550       108
##  7 F7      550_680       108
##  8 F7      680_800       108
##  9 FC5     235_415       108
## 10 FC5     415_550       108
## 11 FC5     550_680       108
## 12 FC5     680_800       108

Summary

ERP analyses were conducted across six time windows, three time-locked to the onset of the first syllable of the target word (F0) and three time-locked to the onset of the suffix. For the F0 analyses, epochs were extracted for the 136–280 ms, 280–400 ms, and 400–600 ms windows over fronto-central electrodes: F3, Fz, FC1, and Cz. For the suffix analyses, epochs were extracted for the 235–415 ms, 415–550 ms, 550–680 ms, and 680–800 ms windows over left-frontal electrodes: F7, F3, and FC5.

For the F0 analysis, in the 136–280 ms time window, a significant group × stress × match interaction was observed, F(1, 29) = 4.68, p = .039. In the 280–400 ms time window, a significant group × stress × match interaction was again observed, F(1, 29) = 4.88, p = .035. In the 400–600 ms time window, a significant stress × match interaction was found, F(1, 29) = 4.96, p = .034, along with a significant group × stress × match interaction, F(1, 29) = 4.89, p = .035.

Estimated marginal means showed a consistent pattern across all three time windows: in the L1 group, match trials elicited more positive amplitudes when the verb was stressed than when it was unstressed, while mismatch trials were negative regardless of stress. The L2 group showed consistently negative amplitudes across all conditions.

For the suffix analysis, no significant effects were found in the 235–415 ms, 415–550 ms, or 550–680 ms time windows. In the 680–800 ms time window, a significant group × stress × match interaction was observed, F(1, 29) = 4.22, p = .049.

Estimated marginal means showed that, in the L1 group, match trials elicited more positive amplitudes when the verb was stressed than when it was unstressed. In mismatch trials, amplitudes were generally negative regardless of stress. The L2 group showed small negative amplitudes across all conditions

Topographic maps illustrate the scalp distribution of the ERP effects observed in the statistical analyses.

For the F0 analysis (stressed – unstressed), L1 participants showed a broad fronto-central positivity for stressed forms relative to unstressed forms across all three time windows (136–600 ms), while L2 participants showed minimal differences and weak negative shifts over central sites.

For the suffix analysis (mismatch – match), L1 participants exhibited a left-frontal positivity for mismatching suffixes in the 550–800 ms windows, with the effect most pronounced in the final window (680–800 ms). In contrast, L2 participants showed a widespread positivity for mismatching suffixes beginning earlier and persisting across all time windows, without clear lateralization.

Time series plots

knitr::include_graphics("ERP_data_onset_F0.jpeg")

knitr::include_graphics("ERP_data_onset_suffix.jpeg")

# Topographic maps

# PrAN – F0 (136–280 ms)
knitr::include_graphics("F0_136_280_L1_stressed.jpeg")

knitr::include_graphics("F0_136_280_L1_unstressed.jpeg")

knitr::include_graphics("F0_136_280_L2_stressed.jpeg")

knitr::include_graphics("F0_136_280_L2_unstressed.jpeg")

# LAN – Suffix (225–400 ms)
knitr::include_graphics("suffix_225_400_L1_match.jpeg")

knitr::include_graphics("suffix_225_400_L1_mismatch.jpeg")

knitr::include_graphics("suffix_225_400_L2_match.jpeg")

knitr::include_graphics("suffix_225_400_L2_mismatch.jpeg")

# P600 – Suffix (500–800 ms)
knitr::include_graphics("suffix_500_800_L1_match.jpeg")

knitr::include_graphics("suffix_500_800_L1_mismatch.jpeg")

knitr::include_graphics("suffix_500_800_L2_match.jpeg")

knitr::include_graphics("suffix_500_800_L2_mismatch.jpeg")

ERP Components

The Pre-activation Negativity (PrAN) is a negative-going ERP component that typically arises between 136–280 ms after the onset of a predictive cue (e.g., the first syllable or tone) and is most pronounced at left-frontal scalp sites. PrAN has been interpreted as an index of form-based lexical prediction, reflecting neural pre-activation of likely continuations based on initial auditory input. The amplitude of PrAN increases when there are fewer possible continuations, indicating higher predictive certainty. This component was first identified in Swedish, where native speakers use lexical tone (word accents) to predict upcoming morphosyntactic suffixes. For example, accent 1 cues suffixes like -en (singular definite) and -er (present tense), while accent 2 cues -ar (plural) or -de (past tense). PrAN is stronger following accent 1, as it is associated with fewer possible suffixes and thus greater predictive certainty.

The Left Anterior Negativity (LAN) is an ERP component typically observed between 225–400 ms after stimulus onset, characterized by a negative deflection over left-frontal scalp regions. It has been associated with morphosyntactic processing, such as subject-verb agreement and grammatical gender violations (Osterhout & Mobley, 1995; Friederici, 2002).

The P600 is a positive-going ERP component that typically emerges between 500–800 ms after the onset of a critical stimulus, often maximal over posterior parietal regions. It has been widely interpreted as reflecting syntactic reanalysis, morphosyntactic repair, or the integration of unpredicted or ungrammatical elements into the ongoing sentence structure (Osterhout & Holcomb, 1992; Hagoort et al., 1993). The amplitude of the P600 increases in response to unexpected or incongruent morphosyntactic cues, such as violations in subject-verb agreement, case marking, or tense morphology.P600 effects have also been observed in response to violations of lexical tone-suffix associations in Swedish, where suffixes that mismatched the tonal expectations of the stem (e.g., accent 1 followed by an accent 2-associated suffix) elicited a robust P600 (Roll et al., 2013; Söderström et al., 2017). These findings suggest that the P600 reflects not only syntactic but also form-based morphophonological prediction errors, particularly when the listener has strong expectations about suffixes based on prosodic cues.